import { defineStore } from 'pinia';
import { getRoot, setRoot, makeInitialData, patchRoot } from './useStorage';
import type { Settings, StorageModel, Theme } from '../types/model';

export const useSettings = defineStore('settings', {
  state: () => ({
    inited: false,
    settings: null as unknown as Settings,
  }),
  getters: {
    theme: (s) => s.settings?.theme ?? 'dark',
  },
  actions: {
    // 工具：浅比较数组是否一致
    _same(a?: string[], b?: string[]) {
      const A = Array.isArray(a) ? a : [];
      const B = Array.isArray(b) ? b : [];
      if (A.length !== B.length) return false;
      for (let i = 0; i < A.length; i++) if (A[i] !== B[i]) return false;
      return true;
    },
    _lastUnpinId: '' as string,
    _lastUnpinAt: 0 as number,
    _saveDockBackup(ids: string[]) {
      try{
        const st: any = (globalThis as any)?.chrome?.storage;
        st?.local?.set?.({ gceDockIdsBackup: Array.isArray(ids) ? ids : [] });
      }catch{}
    },
    async persistDockSettings(allowEmpty: boolean) {
      // 仅用于 Dock 写入：在需要时携带 __dock_allow_empty，避免合并器将合法清空当作误清空拦截
      try {
        const cur = await getRoot();
        await patchRoot({ 
          settings: this.settings,
          engines: (cur as StorageModel | undefined)?.engines,
          bookmarks: (cur as StorageModel | undefined)?.bookmarks,
          groups: (cur as StorageModel | undefined)?.groups,
          __dock_allow_empty: !!allowEmpty,
        } as any);
      } catch (e: any) {
        if (String(e?.message) === 'storage_unavailable') {
          const cur = await getRoot();
          await setRoot(makeInitialData());
          await patchRoot({ 
            settings: this.settings,
            engines: (cur as StorageModel | undefined)?.engines,
            bookmarks: (cur as StorageModel | undefined)?.bookmarks,
            groups: (cur as StorageModel | undefined)?.groups,
            __dock_allow_empty: !!allowEmpty,
          } as any);
        } else { throw e; }
      }
    },
    async sanitizeDock() {
      try{
        const curIds: string[] = Array.isArray((this.settings as any)?.dockIds) ? ((this.settings as any).dockIds as string[]).slice() : [];
        if (!curIds.length) return;
        // 若疑似旧版遗留（icon-*），先不做清洗以避免把用户 Dock 清空
        if (curIds.some((id) => typeof id === 'string' && id.startsWith('icon-'))) return;
        const root = await getRoot();
        const bms = Array.isArray((root as any)?.bookmarks) ? (root as any).bookmarks : [];
        // 书签尚未就绪时不清洗，避免把有效 Dock 误判为空
        if (!Array.isArray(bms) || bms.length === 0) return;
        const validSet = new Set((bms || []).map((b: any) => b?.id).filter(Boolean));
        // 仅按“是否存在于书签集合”判定有效性，不限制前缀
        const next = curIds.filter(id => typeof id === 'string' && validSet.has(id));
        // 安全阈值：不把 Dock 直接清空；且避免一次性大幅度减少（>50%）
        if (next.length === 0) return;
        if (next.length < Math.ceil(curIds.length / 2)) return;
        if (next.length !== curIds.length) {
          (this.settings as any).dockIds = next;
          (this.settings as any).dockStamp = Date.now();
          await this.persistDockSettings(next.length === 0);
          try{ const st: any = (globalThis as any)?.chrome?.storage; st?.local?.set?.({ gceDockIdsBackup: next }); }catch{}
        }
      }catch{}
    },
    async init() {
      if (this.inited) return;
      // 多次重试读取，避免首次刷新时因存储尚未就绪而误判为空并覆盖旧数据
      let root = await getRoot();
      if (!root || !root.settings) {
        for (let i = 0; i < 5 && (!root || !root.settings); i++) {
          await new Promise(res => setTimeout(res, 250));
          root = await getRoot();
        }
        if (!root || !root.settings) {
          // 仍不可用时才初始化，避免意外覆盖已有数据
          root = makeInitialData();
          await setRoot(root);
        }
      }
      this.settings = (root as StorageModel).settings;
      // 保障：dockIds 至少为数组，避免页面刷新初期为 undefined 导致渲染异常
      if (!Array.isArray((this.settings as any).dockIds)) {
        (this.settings as any).dockIds = [];
        try { await patchRoot({ settings: this.settings } as Partial<StorageModel>); } catch {}
      }
      // 保障：dockStamp 存在（用于并发合并时的时间戳优先权）
      if (typeof (this.settings as any).dockStamp !== 'number') {
        try { (this.settings as any).dockStamp = 0; await patchRoot({ settings: this.settings } as Partial<StorageModel>); } catch {}
      }
      // 若 dockIds 为空，尝试从备份键恢复（跨并发写入导致 settings 丢失场景）
      try {
        const st: any = (globalThis as any)?.chrome?.storage;
        if (st?.local?.get) {
          await new Promise<void>((resolve) => {
            try{
              st.local.get(['gceDockIdsBackup'], (res: any) => {
                let backup: string[] = [];
                const raw = res?.gceDockIdsBackup;
                if (Array.isArray(raw)) backup = raw as string[];
                else if (typeof raw === 'string' && raw.trim()) backup = [raw.trim()];
                // 兼容少量用户误写入 JSON 字符串
                else if (typeof raw === 'string') {
                  try{ const arr = JSON.parse(raw); if (Array.isArray(arr)) backup = arr.filter(Boolean); }catch{}
                }
                const cur = Array.isArray((this.settings as any).dockIds) ? (this.settings as any).dockIds as string[] : [];
                if (backup.length && (!cur.length)) {
                  (this.settings as any).dockIds = backup.slice();
                  (this.settings as any).dockStamp = Date.now();
                  patchRoot({ settings: this.settings } as Partial<StorageModel>).finally(()=> resolve());
                } else { resolve(); }
              });
            }catch{ resolve(); }
          });
        }
      } catch {}
      // 监听来自其它上下文（如内容脚本）的存储变更，保持 UI 同步
      try {
        const st: any = (globalThis as any)?.chrome?.storage;
        if (st?.onChanged?.addListener) {
          st.onChanged.addListener((changes: any, area: string) => {
            if (area !== 'local' || !changes || !('localGce' in changes)) return;
            const nv: StorageModel | undefined = changes.localGce?.newValue as StorageModel | undefined;
            if (nv?.settings) {
              const curS: any = this.settings || {};
              const nvS: any = nv.settings || {};
              const next: any = { ...curS, ...nvS };
              // dockIds 合并：基于 dockStamp 决定优先级，并在短窗内忽略“清空覆盖”
              try{
                const cStamp = Number(curS?.dockStamp || 0);
                const nStamp = Number(nvS?.dockStamp || 0);
                const cDock = Array.isArray(curS?.dockIds) ? curS.dockIds : [];
                const nDock = Array.isArray(nvS?.dockIds) ? nvS.dockIds : (("dockIds" in nvS) ? [] : undefined);
                if (nDock !== undefined) {
                  if (nStamp >= cStamp) {
                    const tryingEmpty = Array.isArray(nDock) && nDock.length === 0;
                    const curNonEmpty = Array.isArray(cDock) && cDock.length > 0;
                    const tooClose = (nStamp - cStamp) >= 0 && (nStamp - cStamp) < 5000;
                    if (tryingEmpty && curNonEmpty && tooClose) {
                      next.dockIds = cDock;
                      next.dockStamp = cStamp;
                    } else {
                      next.dockIds = Array.isArray(nDock) ? nDock : [];
                      next.dockStamp = nStamp || Date.now();
                    }
                  } else {
                    next.dockIds = cDock;
                    next.dockStamp = cStamp;
                  }
                } else {
                  next.dockIds = cDock;
                  next.dockStamp = Math.max(cStamp, nStamp);
                }
              }catch{}
              this.settings = next as any;
            }
          });
        }
      } catch {}
      // 迁移：若 dockIds 包含非法条目（如历史遗留的 icon-*），进行一次清洗
      await this.sanitizeDock();
      this.inited = true;
    },
    async setTheme(theme: Theme) {
      this.settings.theme = theme;
      await this.persist();
    },
    async setOpenMode(mode: 'current' | 'newtab') {
      this.settings.openMode = mode;
      await this.persist();
    },
    async setIconSize(size: 'sm' | 'md' | 'lg') {
      this.settings.iconSize = size;
      await this.persist();
    },
    async setColumns(cols: number) {
      this.settings.columns = Math.max(3, Math.min(12, Math.round(cols)));
      await this.persist();
    },
    async setRadius(px: number) {
      this.settings.radius = Math.max(0, Math.min(28, Math.round(px)));
      await this.persist();
    },
    async setShowName(v: boolean) {
      this.settings.showName = v;
      await this.persist();
    },
    async setDockIds(ids: string[]) {
      const uniq = Array.from(new Set(Array.isArray(ids) ? ids : [])).filter(Boolean);
      const prev = Array.isArray((this.settings as any).dockIds) ? (this.settings as any).dockIds as string[] : [];
      // 若无变化则忽略，避免无意义的回波
      if (this._same(prev, uniq)) return;
      (this.settings as any).dockIds = uniq;
      (this.settings as any).dockStamp = Date.now();
      await this.persistDockSettings(uniq.length === 0);
      // 备份到独立键，辅助恢复
      this._saveDockBackup(uniq);
    },
    async unpinDock(id: string) {
      const now = Date.now();
      // 在极短时间内的重复 unpin 同一 ID 直接忽略（去抖）
      if (this._lastUnpinId === id && (now - this._lastUnpinAt) < 800) return;
      this._lastUnpinId = id; this._lastUnpinAt = now;
      const list = Array.isArray((this.settings as any).dockIds) ? (this.settings as any).dockIds.slice() : [];
      const next = list.filter((x: string) => x !== id);
      // 无变化则不写
      if (this._same(list, next)) return;
      (this.settings as any).dockIds = next;
      (this.settings as any).dockStamp = Date.now();
      await this.persistDockSettings(next.length === 0);
      this._saveDockBackup((this.settings as any).dockIds);
    },
    async pinDock(id: string) {
      const list = Array.isArray((this.settings as any).dockIds) ? (this.settings as any).dockIds.slice() : [];
      if (!list.includes(id)) list.push(id);
      (this.settings as any).dockIds = list;
      (this.settings as any).dockStamp = Date.now();
      await this.persistDockSettings(false);
      this._saveDockBackup(list);
    },
    async persist() {
      // 增量写入，避免覆盖 engines/bookmarks 等其它字段
      try {
        const cur = await getRoot();
        await patchRoot({ 
          settings: this.settings,
          engines: (cur as StorageModel | undefined)?.engines,
          bookmarks: (cur as StorageModel | undefined)?.bookmarks,
          groups: (cur as StorageModel | undefined)?.groups,
        } as Partial<StorageModel>);
      } catch (e: any) {
        if (String(e?.message) === 'storage_unavailable') {
          const cur = await getRoot();
          await setRoot(makeInitialData());
          await patchRoot({ 
            settings: this.settings,
            engines: (cur as StorageModel | undefined)?.engines,
            bookmarks: (cur as StorageModel | undefined)?.bookmarks,
            groups: (cur as StorageModel | undefined)?.groups,
          } as Partial<StorageModel>);
        } else { throw e; }
      }
    },
  },
});
